package com.nextive.interview.activity;

import static com.nextive.interview.ApplicationManager.fetchService;
import static com.nextive.interview.activity.view.DefaultTextValuesHolder.fetchValueFor;
import static com.nextive.interview.service.WeightInfoService.DECIMAL_FORMAT;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.nextive.interview.R;
import com.nextive.interview.activity.SetupActivity.SettingsMode;
import com.nextive.interview.dao.WeightInfoDao;
import com.nextive.interview.dto.ContactDetails;
import com.nextive.interview.dto.UserPreferences;
import com.nextive.interview.dto.WeightDateSingleLog;
import com.nextive.interview.service.UserInfoService;
import com.nextive.interview.service.UserInfoService.Metric;
import com.nextive.interview.service.UserInfoService.UserInfoKey;
import com.nextive.interview.service.WeightInfoService;
import com.nextive.interview.util.DateUtil;

/**
 * Activity class to manage the listing of all weight - date entries.
 * 
 * @author Cesar Roman
 *
 */
public class ViewWeightListActivity extends ListActivity {

	/**
	 * Service to obtain weight info data.
	 */
	private WeightInfoService weightInfoService;
	
	/**
	 * Service to obtain user preferences info data.
	 */
	private UserInfoService userInfoService;
	
	/**
	 * Array of weight entry id's.
	 */
	private Long[] idsArray;
	
	/**
	 * Position when header is clicked.
	 */
	private static final int HEADER_CLICK = -1;
	
    /**
     * It takes care of everything that has to be created or bound.
     */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);
		userInfoService = fetchService(UserInfoService.class);
		weightInfoService = fetchService(WeightInfoService.class);
		setContentView(R.layout.weight_table);
		configureWeightTable();
		
		registerForContextMenu(getListView());
		
	}
	
	/**
	 * When resuming populate weight info into the list.
	 */
	@Override
	protected void onResume() {
		
		super.onResume();
		populateWeightInfo();
		
	}

	/**
	 * It creates the context menu. This is done via inflating menu.
	 * It first checks if headers have not been clicked.
	 */
	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		
		if (((AdapterContextMenuInfo) menuInfo).id != HEADER_CLICK) {

			MenuInflater inflater = new MenuInflater(this);
			inflater.inflate(R.menu.list_context_menu, menu);

		}
		
		super.onCreateContextMenu(menu, v, menuInfo);
		
	}
	
	/**
	 * When context item has been selected delete the item or edit it.
	 */
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		
		AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
		switch (item.getItemId()) {
		case R.id.delete_weight_row_id:
			weightInfoService.deleteWeightInfo(idsArray[menuInfo.position - 1]);
			populateWeightInfo();
			return true;
		case R.id.edit_weight_row_id:
			forwardToCreateActivity(idsArray[menuInfo.position - 1]);
			return true;
		}
		
		return super.onContextItemSelected(item);
		
	}

	/**
	 * It creates the options menu. This is done via inflating menu.
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_options_menu, menu);
		return true;
		
	}
	
	/**
	 * If create new option has been selected then forward flow 
	 * to create activity; if settings option has been selected 
	 * then forward flow to setup activity; if share option has 
	 * been selected then forward flow to share activity.
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		switch (item.getItemId()) {
		case R.id.main_create_new:
			forwardToCreateActivity(null);
			return true;
		case R.id.main_settings_menu:
			forwardToSettingsActivity();
			return true;
		case R.id.main_share_menu:
			forwardToShareActivity();
			return true;
		}
		
		return super.onOptionsItemSelected(item);
	}
	
	/**
	 * When an item from the list has been clicked forward flow to edit activity for specified item.
	 * It first checks if headers have not been clicked.
	 */
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		
		if (id !=  HEADER_CLICK) {

			Intent intent = new Intent(this, EditWeightEntryActivity.class);
			intent.putExtra(WeightInfoDao.ID_KEY, ((Map<String, String>) l.getItemAtPosition(position)).
					get(WeightInfoDao.ID_KEY));
			
			startActivity(intent);
			super.onListItemClick(l, v, position, id);

		}
		
	}

	/**
	 * It initializes weight list, inflating its header.
	 */
	private void configureWeightTable() {
		
		ListView weightList = getListView();
		View header = View.inflate(this, R.layout.weight_header_table, null);
		weightList.addHeaderView(header);
		
	}

	/**
	 * It populates all user weight information into the list.
	 */
	private void populateWeightInfo() {
		
		List<WeightDateSingleLog> allWeightDatelogs = weightInfoService.fetchAllWeightInfo();
		idsArray = buildIdsArray(allWeightDatelogs);
		List<Map<String, String>> adapterList = buildAdapterList(allWeightDatelogs);
		
		String[] modelColumns = new String[] { WeightInfoDao.WEIGHT_KEY, WeightInfoDao.DATE_KEY, UserInfoKey.WEIGHT_METRIC.name() };
		int[] viewColumns = new int[] { R.id.weight_column_id, R.id.date_column_id, R.id.metric_column_id };
		
		SimpleAdapter weightListAdapter = new SimpleAdapter(this, adapterList, 
				R.layout.weight_item_table, modelColumns, viewColumns);
		setListAdapter(weightListAdapter);
		
	}
	
	/**
	 * It builds an array of all ids being displayed. This is used later on so to 
	 * know what id to delete/edit.
	 * @param weightDateLogs list of all weight date entries
	 * @return array of all ids
	 */
	private Long[] buildIdsArray(List<WeightDateSingleLog> weightDateLogs) {
		
		Long[] result = new Long[weightDateLogs.size()];
		int i = 0;
		for (WeightDateSingleLog currentLog : weightDateLogs)
			result[i++] = currentLog.getId();
			
		return result;
		
	}
	
	/**
	 * It builds the adapter for the list. This means creating a list of maps with 
	 * keys and values which will map view fields.
	 * @param weightDateLogList
	 * @return adapter list
	 */
	private List<Map<String, String>> buildAdapterList(List<WeightDateSingleLog> weightDateLogList) {
	
		List<Map<String, String>> resultList = new LinkedList<Map<String,String>>();
		if (weightDateLogList != null) {
			
			for (WeightDateSingleLog currentLog : weightDateLogList) {
				
				Map<String, String> rowMap = new HashMap<String, String>();
				rowMap.put(WeightInfoDao.DATE_KEY, DateUtil.generateVisualDate(currentLog.getCalendar(), false));
				rowMap.put(WeightInfoDao.WEIGHT_KEY, DECIMAL_FORMAT.format(currentLog.getWeight()));
				rowMap.put(WeightInfoDao.ID_KEY, currentLog.getId().toString());
				rowMap.put(UserInfoKey.WEIGHT_METRIC.name(), fetchWeightMetricShortDisplay());
				resultList.add(rowMap);
				
			}

		}
		
		return resultList;
		
	}
	
	/**
	 * It forwards flow to create/edit activity.
	 */
	private void forwardToCreateActivity(Long idToEdit) {
		
		Intent intent = new Intent(this, EditWeightEntryActivity.class);
		if (idToEdit != null)
			intent.putExtra(WeightInfoDao.ID_KEY, idToEdit);

		startActivity(intent);
		
	}
	
	/**
	 * It forwards flow to share activity.
	 */
	private void forwardToShareActivity() {
		
		Intent intent = new Intent(this, ShareWeightActivity.class);
		startActivity(intent);
		
	}

	/**
	 * It forwards flow to settings activity. It puts into the intent 
	 * <code>CHANGE_SETTIGNS</code> flag so to be able to update user settings.
	 */
	private void forwardToSettingsActivity() {
		
		Intent intent = new Intent(this, SetupActivity.class);
		intent.putExtra(SettingsMode.CHANGE_SETTINGS.name(), true);
		
		startActivity(intent);
		
	}
	
    /**
     * It goes and fetches user selected metric.
     * @return metric display value
     */
    private String fetchWeightMetricShortDisplay() {
    	
    	UserPreferences preferences = userInfoService.fetchUserInfo();
    	Metric metric = preferences.getMetricOption();
    	
    	return Metric.KG.equals(metric) ? 
    			fetchValueFor(R.string.kg_metric_short).toString() :
    			fetchValueFor(R.string.lb_metric_short).toString();
    	
    }

}
